import event from "../util/NotifierManager";
import { deserialize } from '../util/util';
import { EVENT_SWITCH_2D_VIEW, EVENT_SWITCH_3D_VIEW, INDEX_BLASTFURNACE, INDEX_FURNACE, INDEX_HEAT, INDEX_METER } from "../util/constant";
import * as OpcUa from '../thirdparty/opcua-webapi'

export default class View {
    constructor(view, main) {
        this.url = '';
        this.key = '';
        this.active = false;
        this.tags = [];
        this.tagMap = {};
        this.serverDataMap = {};
        this.btnTags = [];
        this.view = view;
        this.main = main;
        this.uaClient = main.uaClient;
        this.OpcUa = main.OpcUa;
        this.dm = view.dm();

        if (view instanceof ht.graph.GraphView) {
            event.add(EVENT_SWITCH_2D_VIEW, (key) => {
                this.handleSwitch(key);
            });
        }
        if (view instanceof ht.graph3d.Graph3dView) {
            event.add(EVENT_SWITCH_3D_VIEW, (key) => {
                this.handleSwitch(key);
            });
        }
    }
    /**
     * 在这里处理页面切换
     *
     * @param {*} key
     * @memberof View
     */
    handleSwitch(key) {
        if (key === this.key) {
            if (!this.active) {
                this.active = true;
                this.onSetup();
            }
            this.dm.clear();
            deserialize(this, this.url, this.onPostDeserialize.bind(this));
        }
        // 目前是这个场景，执行 tearDown
        else if (this.active) {
            this.onTearDown();
            this.active = false;
        }
    }
    /**
     * 加载这个场景前调用
     */
    onSetup() {
        this.view.mi(this.handleInteractive, this);
        this.view.mp(this.handlePropertyChange, this);
    }
    /**
     * 离开这个场景时会调用
     */
    onTearDown() {
        this.stopRefreshTask();
        this.view.umi(this.handleInteractive, this);
        this.view.ump(this.handlePropertyChange, this);
    }
    /**
     * 加载完场景处理
     */
    onPostDeserialize() {
        console.log(this)
    }
    /**
     * 有需要交互重写此方法
     */
    handleInteractive(e) { }
    /**
     * 监听视图组件属性变化
     */
    handlePropertyChange(e) { }

    /**
     * 根据 this.tags 和 this.tagMap 获取图纸中的节点并存放到this下面
     *
     * @memberof View
     */
    getDatasByTag() {
        this.tags.forEach((tag) => {
            this[tag] = this.dm.getDataByTag(tag);
        });


        for (const tag in this.tagMap) {
            if (Object.prototype.hasOwnProperty.call(this.tagMap, tag)) {
                const info = this.tagMap[tag];
                this[tag] = this.dm.getDataByTag(tag);

            }
        }

    }

    /**
     * 定时器任务，用来从后端读取数据并更新到页面
     *
     * @memberof View
     */
    startRefreshTask() {
        // console.warn('-------------------startRefreshTask-------------')
        this.stopRefreshTask();
        this._refreshTask = setInterval(() => {
            this.readAll();
        }, window.htconfig.Custom.refreshInterval || 5000);
    }

    /**
     * 清除定时刷新任务
     *
     * @memberof View
     */
    stopRefreshTask() {
        this._refreshTask && clearInterval(this._refreshTask);
    }



    /******************************* OPCUA BEGIN ******************************** */

    /**
     * 查找节点的所有子节点
     *
     * @param {*} nodeId
     * @return {*} 
     * @memberof View
     */
    async browseChildrenById(nodeId) {
        const value = await this.uaClient.browseChildren(nodeId);
        return value;
    }

    /**
     * 根据 nodeId 读取当前值
     *
     * @param {*} nodeId
     * @return {*} 
     * @memberof View
     */
    async readValuesById(nodeId) {
        let ids = nodeId;
        if (!Array.isArray(ids)) {
            ids = [nodeId];
        }
        const value = await this.uaClient.readValues(ids);
        return value;
    }

    /**
     * 写操作
     *
     * @param {*} NodesToWrite
     * @return {*} 
     * @memberof View
     */
    async writeValue(NodesToWrite) {
        const rsp = await this.uaClient.writeValues(NodesToWrite);
        let rspText = '写入成功';
        if (rsp && rsp[0] && rsp[0].Code) {
            rspText = OpcUa.StatusUtils.toText(rsp[0].Code); // 获取回复状态
        }
        console.log('---------writeValue rsp---------', rspText, rsp)
        alert(rspText);
        return rsp;
    }



    /**
     * 读取所有数据
     *
     * @memberof Index2dHeat
     */
    async readAll() {
        var self = this;

        // self.OpcUa.ObjectIds.ObjectsFolder 为查询服务端 Objects 文件夹下的对象列表
        const objectsFolder = await self.browseChildrenById(self.OpcUa.ObjectIds.ObjectsFolder);
        // objectsFolder 结构：
        // [
        //     {
        //         "ReferenceTypeId": "i=35",
        //         "IsForward": true,
        //         "NodeId": "i=2253",
        //         "BrowseName": "Server",
        //         "DisplayName": {
        //             "Text": "Server"
        //         },
        //         "NodeClass": 1,
        //         "TypeDefinition": "i=2004"
        //     },
        //     {
        //         "ReferenceTypeId": "i=35",
        //         "IsForward": true,
        //         "NodeId": "nsu=urn:opcfoundation.org:2024-10:starterkit:measurements;s=Measurements",
        //         "BrowseName": "nsu=urn:opcfoundation.org:2024-10:starterkit:measurements;Measurements",
        //         "DisplayName": {
        //             "Text": "Measurements"
        //         },
        //         "NodeClass": 1,
        //         "TypeDefinition": "nsu=urn:opcfoundation.org:2024-10:starterkit:measurements;i=1"
        //     }
        // ]
        // window.DEBUG_MODE && console.log('----- 读取 Objects 文件夹 -----', objectsFolder);

        objectsFolder.forEach(async (item) => {
            if (item.DisplayName && item.DisplayName.Text == 'Measurements') {
                const measurements = await self.browseChildrenById(item.NodeId);
                window.DEBUG_MODE && console.log('----- 读取 Measurements -----', measurements);
                self.handleMeasurementsData(measurements);
            }
        });

        // self.uaClient.readValues(['nsu=urn:opcfoundation.org:2024-10:starterkit:measurements;s=Measurements_Temperature']).then((resp) => {
        //     console.log('----- 读取温度 -----', resp);
        //     const temperatureObj = resp;
        //     // resp 结构：
        //     // {
        //     //     "UaType": 11,
        //     //     "Value": 26.23,
        //     //     "SourceTimestamp": "2025-01-10T06:13:33.489Z"
        //     // }
        // }).catch((e) => {
        //     console.error(e);
        // })
    }

    /**
     * 解析 Measurements 数据，并更新图纸
     *      // objData 结构：
            // [
            //     {
            //         "ReferenceTypeId": "i=47",
            //         "IsForward": true,
            //         "NodeId": "nsu=urn:opcfoundation.org:2024-10:starterkit:measurements;s=Measurements_Temperature",
            //         "BrowseName": "nsu=urn:opcfoundation.org:2024-10:starterkit:measurements;Temperature",
            //         "DisplayName": {
            //             "Text": "Temperature"
            //         },
            //         "NodeClass": 2,
            //         "TypeDefinition": "i=17497"
            //     },
            //     {
            //         "ReferenceTypeId": "i=47",
            //         "IsForward": true,
            //         "NodeId": "nsu=urn:opcfoundation.org:2024-10:starterkit:measurements;s=Measurements_Pressure",
            //         "BrowseName": "nsu=urn:opcfoundation.org:2024-10:starterkit:measurements;Pressure",
            //         "DisplayName": {
            //             "Text": "Pressure"
            //         },
            //         "NodeClass": 2,
            //         "TypeDefinition": "i=17497"
            //     },
            // ]
     * 
     *
     * @param {*} objData
     * @memberof Index2dHeat
     */
    async handleMeasurementsData(objData) {
        if (!objData) {
            return;
        }

        const tags = [];
        /** 一次获取 Measurements 下的所有数据 */
        const nodeIds = [];
        objData.forEach(async (info) => {
            const { NodeId, DisplayName } = info;
            if (!DisplayName || !DisplayName.Text) {
                return
            }
            const tag = DisplayName.Text;
            tags.push(tag);
            nodeIds.push(NodeId);
            this.serverDataMap[NodeId] = info;
            this.serverDataMap[NodeId].tag = tag;
        });
        const values = await this.readValuesById(nodeIds);
        this.handleValueDatas(tags, values, nodeIds);
    }

    /**
     * 将获取的每个数据更新到对应类型的页面节点上
     * @param {*} tags
     * @param {*} values
     * @memberof Index2dHeat
     */
    handleValueDatas(tags, values, nodeIds) {
        // window.DEBUG_MODE && console.log('-------------------------------handleValueDatas----', { tags, values, nodeIds })
        for (let i = 0; i < tags.length; i++) {
            const tag = tags[i];
            const valueObj = values[i];
            const nodeId = nodeIds[i];
            const type = this.tagMap[tag];

            if (this.serverDataMap[nodeId]) {
                this.serverDataMap[nodeId].Value = valueObj;
            }
            // console.log('----handleValueData----', { tag, type, node, valueObj });

            // 根据数据类型更新图纸
            if (typeof type === 'boolean') {
                this.handleUpdateBooleanNode && this.handleUpdateBooleanNode(tag, valueObj, nodeId);
            }

            if (typeof type === 'number') {
                this.handleUpdateNumberNode && this.handleUpdateNumberNode(tag, valueObj, nodeId);
            }

            if (Array.isArray(type)) {
                this.handleUpdateArrayNode && this.handleUpdateArrayNode(tag, valueObj, nodeId);
            }
        }

    }

    /**
     * 图纸切换
     * @param {*} state
     * @memberof Index2dHeat
     */
    onStateChange(state) {
        let main = this.main;
        switch (state) {
            case '高炉':
                main.switch(INDEX_BLASTFURNACE);
                break;
            case '熔保炉':
                main.switch(INDEX_FURNACE);
                break;
            case '换热站':
                main.switch(INDEX_HEAT);
                break;
            case '露天矿':
                main.switch(INDEX_METER);
                break;
            default:
                break;
        }
    }

}

